﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MacomberMapSystem.Common.Serialization;
using MacomberMapSystem.Common.CIM;
using System.Drawing;
using MacomberMapSystem.Common.Database;
using System.Data.Common;
using System.Drawing.Drawing2D;
using MacomberMapSystem.Common.Internals;
using System.Windows.Forms;

namespace MacomberMapSystem.Common.Integration
{
    /// <summary>
    /// This class holds information on a line
    /// </summary>    
    public class MM_Line: MM_Element
    {
        #region Variable declarations
        /// <summary>The TEID of our line</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public UInt64 LineTEID;

        /// <summary>The substation from which the line travels</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public MM_Substation FromSubstation;
        
        /// <summary>The boundary from which the line travels</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public MM_Boundary FromBoundary;

        /// <summary>The substation to which the line travels</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public MM_Substation ToSubstation;
        
        /// <summary>The boundary to which the line travels</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public MM_Boundary ToBoundary;

        /// <summary>The boundaries through which the line travels</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public MM_Boundary[] ThroughBoundaries;

        /// <summary>The KV Level of the line</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public MM_KVLevel KVLevel;

        /// <summary>The coordinates of our transmission line</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public PointD[] Coordinates;

        /// <summary>Whether this line is in the database</summary>
        public bool InDatabase = false;

        /// <summary>Whether the line's coordinates should be publicly displayed</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public bool CoordPublic;


        /// <summary>The bus number associated with the line</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public int BusNumber;
        
        #endregion

        #region Initialization
        /// <summary>
        /// Initilize a new line
        /// </summary>
        /// <param name="dRd"></param>
        /// <param name="Repository"></param>
        public MM_Line(DbDataReader dRd, MM_Repository Repository)
            : base(dRd, Repository)
        {
            InDatabase = true;
            if (FromBoundary == null)
                FromBoundary = FromSubstation.Boundary;
            if (ToBoundary == null)
                ToBoundary = ToSubstation.Boundary;
            if (ThroughBoundaries == null || ThroughBoundaries.Length == 0)
                FindBoundaries(Repository);
        }

        /// <summary>
        /// Locate the boundaries for our repository
        /// </summary>
        /// <param name="Repository"></param>
        public void FindBoundaries(MM_Repository Repository)
        {
            FromBoundary = FromSubstation.Boundary;
            ToBoundary = ToSubstation.Boundary;            
            if (FromBoundary == ToBoundary)
                ThroughBoundaries = new MM_Boundary[] { ToBoundary };
            else
            {
                List<MM_Boundary> OutBounds = new List<MM_Boundary>();
                /*foreach (MM_Boundary Bound in Repository.Db.Boundaries.Values)
                    if (Bound.HitTest(Coordinates))
                        OutBounds.Add(Bound);*/
                ThroughBoundaries = OutBounds.ToArray();
            }
        }

        /// <summary>
        /// Initialize a new line
        /// </summary>
        /// <param name="BaseElement"></param>
        /// <param name="Repository"></param>
        public MM_Line(CIM_Element BaseElement, MM_Repository Repository)
            : base(null, Repository)
        {
            FromSubstation = Repository.Db.Substations[BaseElement.ACSegmentStations[0].rdfID];
            FromBoundary = FromSubstation.Boundary;
            ToSubstation = Repository.Db.Substations[BaseElement.ACSegmentStations[1].rdfID];
            ToBoundary = FromSubstation.Boundary;            
            TEID = Convert.ToUInt64(BaseElement.TEID);
            CIM_Element ParentLine = BaseElement.ParseSingle("cim:Line", null);
            LineTEID = Convert.ToUInt64(ParentLine.TEID);
            Name = Internals.MM_Type_Converter.TitleCase(ParentLine.Name + (ParentLine.InLinks.Length == 1 ? "" : BaseElement.Name));
            rdfID = BaseElement.rdfID;                        
                        
            if (FromBoundary == ToBoundary)
                ThroughBoundaries = new MM_Boundary[] { FromBoundary };
            else
                ThroughBoundaries = new MM_Boundary[] { FromBoundary, ToBoundary };
            KVLevel = Data_Manager.LocateKVLevel(BaseElement.VoltageLevel);
            Coordinates = new PointD[] { FromSubstation.LatLong, ToSubstation.LatLong };
        }
        #endregion

        /// <summary>
        /// Report a human-readable string for our line
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return this.Name + " (" + FromSubstation.LongName + " to " + ToSubstation.LongName + ")";
        }

        /// <summary>
        /// Write out our menu elements for this line
        /// </summary>
        /// <param name="Menu"></param>
        public void WriteMenuElements(ContextMenuStrip Menu)
        {
            Menu.Items.Add("Line " + FromSubstation.LongName + " to " + "Substation " + ToSubstation.LongName);
            Menu.Items.Add("   TEID: " + TEID.ToString());
            Menu.Items.Add("   rdf:ID: " + rdfID.ToString());
            Menu.Items.Add("   From: " + FromSubstation.LongName + " (" + FromBoundary.Name + ")");
            if (!ToSubstation.Equals(FromSubstation))
                Menu.Items.Add("   To: " + ToSubstation.LongName + " (" + ToBoundary.Name + ")");


            StringBuilder sB = new StringBuilder();
            foreach (MM_Boundary Bound in ThroughBoundaries)
                if (!FromBoundary.Equals(Bound) && !ToBoundary.Equals(Bound))
                    sB.Append((sB.Length == 0 ? "" : ",") + Bound.Name);
            if (sB.Length > 0)
                Menu.Items.Add("  Through: " + sB.ToString());
            if (ValidatedOn.ToOADate() == 0)
                Menu.Items.Add("  Never validated.");
            else
                Menu.Items.Add("  Last validated: " + ValidatedOn.ToShortDateString() + " by " + ValidatedBy.Nickname);                                          
        }

        /// <summary>
        /// Write our tooltip information out
        /// </summary>
        /// <param name="tTip"></param>
        public String WriteToolTip(ToolTip tTip)
        {
            tTip.ToolTipIcon = ToolTipIcon.Info;
            tTip.ToolTipTitle = "Line " + FromSubstation.LongName + " to " + "Substation " + ToSubstation.LongName;
            StringBuilder sB = new StringBuilder();                       
            foreach (MM_Boundary Bound in ThroughBoundaries)
                if (!FromBoundary.Equals(Bound) && !ToBoundary.Equals(Bound))
                    sB.Append((sB.Length == 0 ? "" : ",") + Bound.Name);
            if (sB.Length > 0)
                sB.AppendLine("  Through: " + sB.ToString());
            if (ValidatedOn.ToOADate() == 0)
                sB.AppendLine("  Never validated.");
            else
                sB.AppendLine("  Last validated: " + ValidatedOn.ToShortDateString() + " by " + ValidatedBy.Nickname);                                                                                  
            return sB.ToString();
        }
    }
}
